﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using vJoyInterfaceWrap;

namespace N64Joy
{
    public partial class Form1 : Form
    {
        // Declaring one joystick (Device id 1) and a position structure. 
        static public vJoy joystick;
        static public vJoy.JoystickState iReport;
        static public uint id = 1;

        public Form1()
        {
            InitializeComponent();

            comboBox1.DataSource = SerialPort.GetPortNames();            
        }

        private void button1_Click(object sender, EventArgs e)
        {
            comboBox1.DataSource = SerialPort.GetPortNames();         
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // Create one joystick object and a position structure.
            joystick = new vJoy();
            iReport = new vJoy.JoystickState();


            // Get the driver attributes (Vendor ID, Product ID, Version Number)
            if (!joystick.vJoyEnabled())
            {
                MessageBox.Show("vJoy driver not enabled: Failed Getting vJoy attributes.\n");
                return;
            }
            //else
            //    Console.WriteLine("Vendor: {0}\nProduct :{1}\nVersion Number:{2}\n", joystick.GetvJoyManufacturerString(), joystick.GetvJoyProductString(), joystick.GetvJoySerialNumberString());

            // Get the state of the requested device
            VjdStat status = joystick.GetVJDStatus(id);
            switch (status)
            {
                case VjdStat.VJD_STAT_OWN:
                    MessageBox.Show(string.Format("vJoy Device {0} is already owned by this feeder\n", id));
                    break;
                case VjdStat.VJD_STAT_FREE:
                    //MessageBox.Show(string.Format("vJoy Device {0} is free\n", id));
                    break;
                case VjdStat.VJD_STAT_BUSY:
                    MessageBox.Show(string.Format("vJoy Device {0} is already owned by another feeder\nCannot continue\n", id));
                    return;
                case VjdStat.VJD_STAT_MISS:
                    MessageBox.Show(string.Format("vJoy Device {0} is not installed or disabled\nCannot continue\n", id));
                    return;
                default:
                    MessageBox.Show(string.Format("vJoy Device {0} general error\nCannot continue\n", id));
                    return;
            };

            // Check which axes are supported
            bool AxisX = joystick.GetVJDAxisExist(id, HID_USAGES.HID_USAGE_X);
            bool AxisY = joystick.GetVJDAxisExist(id, HID_USAGES.HID_USAGE_Y);
            //bool AxisZ = joystick.GetVJDAxisExist(id, HID_USAGES.HID_USAGE_Z);
            //bool AxisRX = joystick.GetVJDAxisExist(id, HID_USAGES.HID_USAGE_RX);
            //bool AxisRZ = joystick.GetVJDAxisExist(id, HID_USAGES.HID_USAGE_RZ);
            //// Get the number of buttons and POV Hat switchessupported by this vJoy device
            //int nButtons = joystick.GetVJDButtonNumber(id);
            //int ContPovNumber = joystick.GetVJDContPovNumber(id);
            //int DiscPovNumber = joystick.GetVJDDiscPovNumber(id);

            // Print results
            if (!AxisX || !AxisY)
            {
                MessageBox.Show("Controller does not have X and Y axes. Configure vJoy please");
            }

            int nButtons = joystick.GetVJDButtonNumber(id);

            if (nButtons != 14)
            {
                MessageBox.Show("Controller not configured for 14 buttons. Reconfigure vJoy please");
            }

            // Acquire the target
            if ((status == VjdStat.VJD_STAT_OWN) || ((status == VjdStat.VJD_STAT_FREE) && (!joystick.AcquireVJD(id))))
            {
                MessageBox.Show(string.Format("Failed to acquire vJoy device number {0}.\n", id));
                return;
            }
            //else
            //    Console.WriteLine("Acquired: vJoy device number {0}.\n", id);

            //Console.WriteLine("\npress enter to stat feeding");
            //Console.ReadKey(true);

          
            maxval = 0;

            joystick.GetVJDAxisMax(id, HID_USAGES.HID_USAGE_X, ref maxval);

            // Reset this device to default values
            joystick.ResetVJD(id);

            com = new System.IO.Ports.SerialPort(comboBox1.Text, 115200);
            com.Open();


            button2.Enabled = false;
            backgroundWorker1.RunWorkerAsync();
            
        }

        private long maxval;
        private System.IO.Ports.SerialPort com;

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {                
                while (true)
                {
                    bool res;
                    string N64_data = com.ReadLine();
                    if (N64_data.Length < 20)
                    {
                        System.Threading.Thread.Sleep(10);
                        continue;
                    }
                    //Console.WriteLine(N64_data);
                    bool
                        N64_A = N64_data[0] == '4',
                        N64_B = N64_data[1] == '4',
                        N64_Z = N64_data[2] == '4',
                        N64_ST = N64_data[3] == '4',
                        N64_UP = N64_data[4] == '4',
                        N64_DOWN = N64_data[5] == '4',
                        N64_LEFT = N64_data[6] == '4',
                        N64_RIGHT = N64_data[7] == '4',
                        N64_L = N64_data[10] == '4',
                        N64_R = N64_data[11] == '4',
                        N64_CUP = N64_data[12] == '4',
                        N64_CDOWN = N64_data[13] == '4',
                        N64_CLEFT = N64_data[14] == '4',
                        N64_CRIGHT = N64_data[15] == '4';

                    string[] N64_xy = N64_data.Substring(16).Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                    sbyte N64_xS = sbyte.Parse(N64_xy[0]);
                    sbyte N64_yS = sbyte.Parse(N64_xy[1]);

                    // axis values come in 8 bits each, -128 to 127 . First
                    // convert them to range 0 - 255, and then 
                    // convert to range 0 - maxval .

                    byte N64_xb = (byte)((byte)N64_xS - 128);
                    byte N64_yb = (byte)((byte)-N64_yS - 128);

                    long N64_x = (long)Math.Round(maxval * (N64_xb / 255.0));
                    long N64_y = (long)Math.Round(maxval * (N64_yb / 255.0));


                    // Set position of 4 axes
                    res = joystick.SetAxis((int)N64_x, id, HID_USAGES.HID_USAGE_X);
                    res = joystick.SetAxis((int)N64_y, id, HID_USAGES.HID_USAGE_Y);
                    //res = joystick.SetAxis(Z, id, HID_USAGES.HID_USAGE_Z);
                    //res = joystick.SetAxis(XR, id, HID_USAGES.HID_USAGE_RX);
                    //res = joystick.SetAxis(ZR, id, HID_USAGES.HID_USAGE_RZ);

                    // Press/Release Buttons
                    res = joystick.SetBtn(N64_A, id, 1);
                    res = joystick.SetBtn(N64_B, id, 2);
                    res = joystick.SetBtn(N64_Z, id, 3);
                    res = joystick.SetBtn(N64_ST, id, 4);
                    res = joystick.SetBtn(N64_UP, id, 5);
                    res = joystick.SetBtn(N64_DOWN, id, 6);
                    res = joystick.SetBtn(N64_LEFT, id, 7);
                    res = joystick.SetBtn(N64_RIGHT, id, 8);
                    res = joystick.SetBtn(N64_L, id, 9);
                    res = joystick.SetBtn(N64_R, id, 10);
                    res = joystick.SetBtn(N64_CUP, id, 11);
                    res = joystick.SetBtn(N64_CDOWN, id, 12);
                    res = joystick.SetBtn(N64_CLEFT, id, 13);
                    res = joystick.SetBtn(N64_CRIGHT, id, 14);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                button1.Invoke(new Action(enablebtn));
                joystick.RelinquishVJD(id);
            }
        }



        public void enablebtn()
        {
            button2.Enabled = true;
        }
    }


}
